package client

import (
	"CheRpc/encode"
	"encoding/json"
	"fmt"
	"net"
	"reflect"
	"strconv"
	"strings"
	"sync"
)

type Client struct {
	LocalCode interface{}
	Conn      net.Conn
	untity    *encode.Untily
	L         sync.Mutex
}

func (cli *Client) Bind(add string) {
	con, err := net.Dial("tcp", add)
	if err != nil {
		panic(err)
	}
	cli.Conn = con
	go cli.Read()
}
func (cli *Client) Read() {
	for {
		res := make([]byte, 512)

		cli.Conn.Read(res)

		cli.doRequest(res)
	}
}

var ResChanle chan []string = make(chan []string, 10)

func (cli *Client) doRequest(meg []byte) {
	//msg := encode.RequestMeg{}
	ReqLen := cli.untity.BytesToInt(meg[:4])
	ReqId := cli.untity.BytesToInt(meg[4:8])
	if ReqLen == 0 {
		return
	}
	if ReqId == 0 {

		callbody := encode.CallBody{}
		json.Unmarshal(meg[8:8+ReqLen], &callbody)
		re := cli.CallLocalMethod(&callbody)

		cli.Conn.Write(cli.writeMeg(4, []byte(callbody.Method+"|"+strconv.Itoa(int(re[0].Int())))))
	} else if ReqId == 4 {
		ResChanle <- strings.Split(string(meg[8:8+ReqLen]), "|")

	}
}
func (cli *Client) CallLocalMethod(call *encode.CallBody) []reflect.Value {
	obj := reflect.ValueOf(cli.LocalCode)
	m := obj.MethodByName(strings.Split(call.Method, ".")[1])
	//var agr []reflect.Value = []reflect.Value{reflect.ValueOf(1), reflect.ValueOf(1)}
	fmt.Println(call.Method)
	var agr []reflect.Value = []reflect.Value{reflect.ValueOf(int(call.Agre[0].(float64))), reflect.ValueOf(int(call.Agre[1].(float64)))}
	return m.Call(agr)
}

//填充消息
func (cli *Client) writeMeg(req int, bodys []byte) []byte {
	SendByte := make([]byte, 256)

	lens := cli.untity.IntToBytes(len(bodys))
	reqByte := cli.untity.IntToBytes(req)
	SendByte[0] = lens[0]
	SendByte[1] = lens[1]
	SendByte[2] = lens[2]
	SendByte[3] = lens[3]
	SendByte[4] = reqByte[0]
	SendByte[5] = reqByte[1]
	SendByte[6] = reqByte[2]
	SendByte[7] = reqByte[3]
	index := 8
	for i := 0; i < len(bodys); i++ {
		SendByte[index] = bodys[i]
		index += 1
	}
	return SendByte

}
func (cli *Client) Call(body *encode.CallBody) string {
	bodys, _ := json.Marshal(body)
	cli.untity = &encode.Untily{}

	megbody := cli.writeMeg(0, bodys)

	//
	cli.L.Lock()
	cli.Conn.Write(megbody)

	defer cli.L.Unlock()

	a := <-ResChanle
	if a[0] == body.Method {

		return string(a[1])

	}
	return ""
}
func (cli *Client) Regist(code interface{}, body *encode.ResistBody) {
	bodys, _ := json.Marshal(body)
	cli.untity = &encode.Untily{}
	cli.LocalCode = code
	megbody := cli.writeMeg(1, bodys)

	cli.Conn.Write(megbody)

}
func (cli *Client) GetServer() {
	megbody := cli.writeMeg(2, []byte(""))
	cli.Conn.Write(megbody)
}
